package org.xacmlauth.service;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.herasaf.xacml.core.api.PDP;
import org.herasaf.xacml.core.context.RequestMarshaller;
import org.herasaf.xacml.core.context.ResponseMarshaller;
import org.herasaf.xacml.core.context.impl.RequestType;
import org.herasaf.xacml.core.context.impl.ResponseType;
import org.herasaf.xacml.core.policy.Evaluatable;
import org.herasaf.xacml.core.policy.PolicyMarshaller;
import org.herasaf.xacml.core.simplePDP.MapBasedSimplePolicyRepository;
import org.herasaf.xacml.core.simplePDP.SimplePDPConfiguration;
import org.herasaf.xacml.core.simplePDP.SimplePDPFactory;
import org.herasaf.xacml.core.simplePDP.initializers.InitializerExecutor;
import org.springframework.stereotype.Service;
import org.springframework.xml.transform.StringSource;
import org.xacmlauth.dao.DAOFactory;
import org.xacmlauth.dao.PolicyDAO;
import org.xacmlauth.dto.PolicyDTO;

@Service
public class AuthServiceImp implements AuthService {
	
	private static final Log LOG = LogFactory.getLog(AuthServiceImp.class);

	@Override
	public boolean registerPolicy(PolicyDTO policy) {
		boolean isSuccess = false;
		
		PolicyDAO policyDAO = DAOFactory.getDAOFactory().getPolicyDAO();
		
		List<PolicyDTO> policyList = new ArrayList<PolicyDTO>();
		try {
			policyList.add(policy);
			isSuccess = policyDAO.registerPolicy(policyList);
		} catch (Exception e) {
			LOG.error("Policy Registration Error", e);
		}
		
		return isSuccess;
	}

	@Override
	public String enforce(String clientID, String request) {
		String response = null;
		try {
			
			InitializerExecutor.runInitializers();
			
			SimplePDPConfiguration configuration = new SimplePDPConfiguration();
			MapBasedSimplePolicyRepository policyRetrievalPoint = new MapBasedSimplePolicyRepository();
			
			PolicyDAO policyDAO = DAOFactory.getDAOFactory().getPolicyDAO();
			List<PolicyDTO> policyList = policyDAO.findPolicies(clientID);
			List<Evaluatable> evaluatableList = new ArrayList<Evaluatable>();
			
			for(PolicyDTO policy : policyList){
				Evaluatable evaluatable = PolicyMarshaller.unmarshal(new StringSource(policy.getContent()));
				evaluatableList.add(evaluatable);
			}
			
			policyRetrievalPoint.deploy(evaluatableList);
			
			configuration.setPolicyRetrievalPoint(policyRetrievalPoint);
			
			PDP pdp = SimplePDPFactory.getSimplePDP(configuration);
			
			RequestType req = RequestMarshaller.unmarshal(new StringSource(request));
			ResponseType res = pdp.evaluate(req);
			
			StringWriter writer = new StringWriter();
			ResponseMarshaller.marshal(res, writer);
			
			response = writer.toString();
			
			System.out.println("#############################################");
			System.out.println(response);
			System.out.println("#############################################");
			
		} catch (Exception e) {
			LOG.error("Policy Enforcement Error", e);
		}
		
		return response;
	}

	@Override
	public List<PolicyDTO> listPolicies(String clientID) {
		PolicyDAO policyDAO = DAOFactory.getDAOFactory().getPolicyDAO();
		List<PolicyDTO> policyContentList = new ArrayList<PolicyDTO>();
		try {
			policyContentList = policyDAO.findPolicies(clientID);
		} catch (Exception e) {
			LOG.error("Policy listing error", e);
		}
		
		return policyContentList;
	}

	@Override
	public boolean deletePolicy(String clientID) {
		PolicyDAO policyDAO = DAOFactory.getDAOFactory().getPolicyDAO();
		boolean status = false;
		
		try {
			status = policyDAO.deletePolicies(clientID);
		} catch (Exception e) {
			LOG.error("Policy listing error", e);
		}
		
		return status;
	}

}
